// 注意：
// 对于 rtos 封装的 thread 类
// 禁止在关中断的场景下进行析构操作

#ifndef xpack_concurrency_thread
#define xpack_concurrency_thread
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::concurrency_thread::inc
#include"concurrency/lock/atom_swap.hpp"
#include"configure/switch.hpp"
#include"define/base_type.hpp"
#include"dumb/disable_copy.hpp"
#include"dumb/move.hpp"
#include"interface/can_callback.hpp"
#include"macro/xexport.hpp"
#include"macro/xmodify.hpp"
#include"macro/xnew.hpp"
#include"macro/xstruct.hpp"
#include"macro/xunlikely.hpp"
#include"memop/cast.hpp"
#include"meta/is_empty_class.hpp"
#include"utils/memory.hpp"
#pragma pop_macro("xuser")

namespace mixc::concurrency_thread{
    using lambda_call = void(*)(voidp lambda);

    enum : uxx{
        detached_bit = 1,
        mask_ignore_detached_bit = ~detached_bit,
    };

    xstruct(
        xname(clambda_meta),
        xpubf(m_bytes,        uxx),
        xpubf(m_handler,      voidp),
        xpubf(m_call,         lambda_call),
        xpubf(m_release,      lambda_call),
        xpubf(m_sem,          voidp[xuse_mixc_rtos ? 1 : 2])
        // this + 1 定位到 lambda 参数的偏移
    )
        void invoke() const {
            auto call               = m_call;
            auto args               = voidp(this + 1);
            call(args);
        }

        void handler(voidp value){
            m_handler               = value;
        }

        voidp handler() const {
            return m_handler;
        }

        void semaphore_for_join(voidp value){
            m_sem[0]                = value;
        }

        voidp semaphore_for_join() const {
            return m_sem[0];
        }

    #if xuse_mixc_rtos == 0
        void semaphore_for_suspend(voidp value){
            m_sem[1]                = value;
        }

        voidp semaphore_for_suspend() const {
            return m_sem[1];
        }
    #endif
    $

    xstruct(
        xname(clambda),
        xprof(m_lambda, clambda_meta *)
    )
        clambda() : m_lambda(nullptr){}

        template<class lambda_t>
        requires(inc::can_callback<lambda_t, void()>)
        clambda(lambda_t const & lambda, bool is_detached){
            struct closure{
                static void call(voidp lambda){
                    ((lambda_t *)lambda)->operator()();
                }

                static void release(voidp lambda){
                    ((lambda_t *)lambda)->~lambda_t();
                }
            };

            auto args_bytes         = inc::is_empty_class<lambda_t> ? 0 : sizeof(lambda_t);
            auto total_bytes        = inc::memory::size{ args_bytes + sizeof(clambda_meta) };

            if (m_lambda = inc::memory::alloc<clambda_meta>(total_bytes);
                m_lambda == nullptr){
                im_initialize_fail();
                return;
            }

            xnew(m_lambda + 1) lambda_t(
                inc::move(lambda)
            );

            m_lambda->m_bytes       = total_bytes;
            m_lambda->m_call        = & closure::call;
            m_lambda->m_release     = & closure::release;
            m_lambda->m_sem[0]      = nullptr;
            m_lambda->m_handler     = nullptr;

        #if xuse_mixc_rtos == 0
            m_lambda->m_sem[1]      = nullptr;
        #endif

            static_assert(sizeof(clambda) == sizeof(uxx));
            inc::cast<uxx>(m_lambda)|= is_detached ? 1 : 0;
        }

        bool is_detached() const {
            static_assert(sizeof(clambda) == sizeof(uxx));
            return (uxx(m_lambda) & detached_bit) != 0;
        }

        bool is_valid() const {
            return m_lambda != nullptr && uxx(m_lambda) != not_exist;
        }

        bool is_initialize_failed() const {
            return uxx(m_lambda) == not_exist;
        }

        void im_initialize_fail() const {
            // 不提供 is_initialize_failed(false) 接口
            // 会覆盖 clambda::m_lambda 原有指针的内容
            m_lambda                = (clambda_meta *)(not_exist);
        }

        void release() const {
            static_assert(sizeof(clambda) == sizeof(uxx));
            auto adjust             = (clambda_meta *)(uxx(m_lambda) & mask_ignore_detached_bit);
            auto call               = adjust->m_release;
            auto args               = voidp(adjust + 1);
            call(args);
            inc::memory::free(adjust, inc::memory::size{adjust->m_bytes});
            m_lambda                = nullptr;
        }

        // 内存矫正，最低位用于指示是否是分离线程
        clambda_meta * operator->() const {
            static_assert(sizeof(clambda) == sizeof(uxx));
            auto adjust             = (clambda_meta *)(uxx(m_lambda) & mask_ignore_detached_bit);
            return adjust;
        }
    $

    template<bool is_detached_v>
    struct sugar{
        template<class lambda_t>
        clambda operator *(lambda_t const & lambda){
            return { lambda, is_detached_v };
        }
    };
}

namespace mixc::concurrency_thread::origin{
    xstruct(
        xname(thread),
        xpubb(inc::disable_copy),
        xprif(m_lambda, clambda)
    )
        thread()                    = default;
        thread(thread && self) : 
            m_lambda(inc::atom_swap(xmodify(self.m_lambda), clambda{})){
        }
        thread(clambda && lambda);
       ~thread();

        the_t && hand_over(){
            return (the_t &&)xthe;
        }

        void operator=(thread && self){
            xunlikely(this == & self){
                return;
            }

            if (m_lambda.is_valid() and not m_lambda.is_detached()){
                this->~thread();
            }

            m_lambda = inc::atom_swap(xmodify(self.m_lambda), clambda{});
        }

        bool is_initialize_failed() const {
            return m_lambda.is_initialize_failed();
        }

        uxx id() const {
        #if xuse_mixc_rtos
            return m_lambda.is_valid() ? uxx(m_lambda->handler()) : not_exist;
        #else
            return inc::cast<uxx>(m_lambda);
        #endif
        }

        void resume();
    $
}

#define xjoinable                   ::mixc::concurrency_thread::sugar<false>() * [=]() mutable
#define xdetached                   ::mixc::concurrency_thread::sugar<true >() * [=]() mutable
#define xjoinable_global            ::mixc::concurrency_thread::sugar<false>() * []()
#define xdetached_global            ::mixc::concurrency_thread::sugar<true >() * []()

#define xjoinablex(...)             ::mixc::concurrency_thread::sugar<false>() * [=]() mutable { (__VA_ARGS__)(); }
#define xdetachedx(...)             ::mixc::concurrency_thread::sugar<true >() * [=]() mutable { (__VA_ARGS__)(); }
#define xjoinable_globalx(...)      ::mixc::concurrency_thread::sugar<false>() * []() { (__VA_ARGS__)(); }
#define xdetached_globalx(...)      ::mixc::concurrency_thread::sugar<true >() * []() { (__VA_ARGS__)(); }

#endif

xexport_space(mixc::concurrency_thread::origin)
